from ctypes import CDLL, RTLD_GLOBAL
from bcat.ffi.error import LoadingError


class Loader(object):
    def __init__(self, sos=None):
        if sos is None:
            sos = {}
        self.__sos = sos

    # @override
    def load(self):
        return self

    def get(self, path):
        return self.__sos[path]

    def __str__(self):
        return " ".join(self.__sos.keys())

    def _shared_object_paths(self):
        return self.__sos


# the dependent so of the target_so can be found by the System Loader(sos must be in the LD_LIBRARY_PATH or
# system-libs path)
class SharedObjectsLoader(Loader):
    def __init__(self, so_pathes):
        super(SharedObjectsLoader, self).__init__({})
        self.__so_pathes = so_pathes

    @staticmethod
    def from_one(so_path):
        return SharedObjectsLoader([so_path])

    @staticmethod
    def from_many(so_paths: list):
        return SharedObjectsLoader(so_paths)

    def load(self):
        try:
            for path in self.__so_pathes:
                self._shared_object_paths()[path] = CDLL(path, mode=RTLD_GLOBAL)  # OSError
        except Exception as e:
            raise LoadingError("loading path error: so_pathes:{}, exception:[{}]".format(self.__so_pathes, e))
        return self


import unittest
import os


# @unittest.skip("loader skip")
class TestSharedObjectsLoader(unittest.TestCase):
    def test_loader_one_so(self):
        target_name = "libsge_api.so"
        loader = SharedObjectsLoader.from_one(target_name).load()
        self.assertIsNotNone(loader)

    def test_loader_many_so(self):
        dll_pathes = [
            'libeasy.so',
            'liblogger.so',
            "libapi_framework.so",
            "libsge_api.so",
        ]
        loader = SharedObjectsLoader.from_many(dll_pathes).load()
        self.assertIsNotNone(loader)

    @unittest.skip("absolute path")
    def test_loader_with_abspath(self):
        target_full_path = os.path.dirname(os.path.abspath(__file__)) + '/c/libs/libsge_api.so'
        loader = SharedObjectsLoader.from_one(target_full_path)
        self.assertIsNotNone(loader)
